//=============================================================================
// main.js v1.9.0
// 游戏主入口文件，负责加载必要资源、初始化环境并启动游戏
//=============================================================================

// 需要加载的脚本文件列表，按顺序加载
const scriptUrls = [
    "js/libs/pixi.js",               // 2D渲染引擎
    "js/libs/pako.min.js",           // 压缩/解压库
    "js/libs/localforage.min.js",    // 本地存储库
    "js/libs/effekseer.min.js",      // 特效引擎
    "js/libs/vorbisdecoder.js",      // 音频解码库
    "js/rmmz_core.js",               // 核心功能模块
    "js/rmmz_managers.js",           // 管理器模块
    "js/rmmz_objects.js",            // 对象定义模块
    "js/rmmz_scenes.js",             // 场景模块
    "js/rmmz_sprites.js",            // 精灵模块
    "js/rmmz_windows.js",            // 窗口模块
    "js/plugins.js"                  // 插件模块
];

// Effekseer特效引擎的WebAssembly文件路径
const effekseerWasmUrl = "js/libs/effekseer.wasm";

/**
 * 主程序类，负责协调游戏初始化的整个流程
 */
class Main {
    constructor() {
        this.xhrSucceeded = false;   // XMLHttpRequest测试是否成功
        this.loadCount = 0;          // 已加载的脚本数量
        this.error = null;           // 存储初始化过程中发生的错误
    }

    /**
     * 启动主程序
     */
    run() {
        // this.showLoadingSpinner();   // 显示加载动画
        this.testXhr();              // 测试XMLHttpRequest功能
        this.hookNwjsClose();        // 处理NW.js环境下的窗口关闭事件
        this.loadMainScripts();      // 加载主要脚本文件
    }

    /**
     * 创建并显示加载动画元素
     */
    showLoadingSpinner() {
        const loadingSpinner = document.createElement("div");
        const loadingSpinnerImage = document.createElement("div");
        loadingSpinner.id = "loadingSpinner";         // 加载容器ID
        loadingSpinnerImage.id = "loadingSpinnerImage"; // 加载动画元素ID
        loadingSpinner.appendChild(loadingSpinnerImage);
        document.body.appendChild(loadingSpinner);    // 添加到页面
    }

    /**
     * 移除加载动画元素
     */
    eraseLoadingSpinner() {
        const loadingSpinner = document.getElementById("loadingSpinner");
        if (loadingSpinner) {
            document.body.removeChild(loadingSpinner);
        }
    }

    /**
     * 测试XMLHttpRequest是否可用（用于检测浏览器本地文件访问权限）
     */
    testXhr() {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", document.currentScript.src);  // 请求当前脚本
        xhr.onload = () => (this.xhrSucceeded = true); // 成功则标记
        xhr.send();
    }

    /**
     * 处理NW.js环境下的窗口关闭事件（解决进程无法正常终止的问题）
     */
    hookNwjsClose() {
        // [注意] 在关闭窗口时，NW.js进程有时无法正常终止
        // 这段代码是为了解决这个问题的变通方法
        if (typeof nw === "object") {
            nw.Window.get().on("close", () => nw.App.quit());
        }
    }

    /**
     * 加载所有主脚本文件
     */
    loadMainScripts() {
        for (const url of scriptUrls) {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = url;
            script.async = false;  // 同步加载，保证执行顺序
            script.defer = true;   // 延迟执行
            script.onload = this.onScriptLoad.bind(this);  // 加载成功回调
            script.onerror = this.onScriptError.bind(this); // 加载失败回调
            script._url = url;     // 存储URL用于错误信息
            document.body.appendChild(script);
        }
        this.numScripts = scriptUrls.length;  // 总脚本数量
        
        // 监听窗口加载完成和错误事件
        window.addEventListener("load", this.onWindowLoad.bind(this));
        window.addEventListener("error", this.onWindowError.bind(this));
    }

    /**
     * 脚本加载成功回调
     */
    onScriptLoad() {
        // 所有脚本加载完成后初始化插件管理器
        if (++this.loadCount === this.numScripts) {
            PluginManager.setup($plugins);
        }
    }

    /**
     * 脚本加载失败回调
     * @param {Event} e - 错误事件对象
     */
    onScriptError(e) {
        this.printError("Failed to load", e.target._url);
    }

    /**
     * 显示错误信息
     * @param {string} name - 错误名称
     * @param {string} message - 错误消息
     */
    printError(name, message) {
        // this.eraseLoadingSpinner();  // 移除加载动画
        
        // 如果还没有错误显示元素，则创建并添加到页面
        if (!document.getElementById("errorPrinter")) {
            const errorPrinter = document.createElement("div");
            errorPrinter.id = "errorPrinter";
            errorPrinter.innerHTML = this.makeErrorHtml(name, message);
            document.body.appendChild(errorPrinter);
        }
    }

    /**
     * 创建错误信息的HTML内容
     * @param {string} name - 错误名称
     * @param {string} message - 错误消息
     * @returns {string} 错误信息的HTML字符串
     */
    makeErrorHtml(name, message) {
        const nameDiv = document.createElement("div");
        const messageDiv = document.createElement("div");
        nameDiv.id = "errorName";
        messageDiv.id = "errorMessage";
        nameDiv.innerHTML = name;
        messageDiv.innerHTML = message;
        return nameDiv.outerHTML + messageDiv.outerHTML;
    }

    /**
     * 窗口加载完成回调
     */
    onWindowLoad() {
        // 检查各种可能的错误情况
        if (!this.xhrSucceeded) {
            const message = "Your browser does not allow to read local files.";
            this.printError("Error", message);
        } else if (this.isPathRandomized()) {
            const message = "Please move the Game.app to a different folder.";
            this.printError("Error", message);
        } else if (this.error) {
            this.printError(this.error.name, this.error.message);
        } else {
            // 所有检查通过，初始化Effekseer特效引擎
            this.initEffekseerRuntime();
        }
    }

    /**
     * 窗口错误事件回调
     * @param {ErrorEvent} event - 错误事件对象
     */
    onWindowError(event) {
        // 只记录第一个发生的错误
        if (!this.error) {
            this.error = event.error;
        }
    }

    /**
     * 检查游戏是否被放置在随机路径下（macOS Gatekeeper路径随机化问题）
     * @returns {boolean} 是否在随机路径下
     */
    isPathRandomized() {
        // [注意] 当Gatekeeper路径随机化生效时，我们无法正确保存游戏
        return (
            typeof process === "object" &&
            process.mainModule.filename.startsWith("/private/var")
        );
    }

    /**
     * 初始化Effekseer特效引擎运行时
     */
    initEffekseerRuntime() {
        const onLoad = this.onEffekseerLoad.bind(this);
        const onError = this.onEffekseerError.bind(this);
        effekseer.initRuntime(effekseerWasmUrl, onLoad, onError);
    }

    /**
     * Effekseer初始化成功回调
     */
    onEffekseerLoad() {
        // this.eraseLoadingSpinner();  // 移除加载动画
        SceneManager.run(Scene_Boot); // 启动游戏引导场景
    }

    /**
     * Effekseer初始化失败回调
     */
    onEffekseerError() {
        this.printError("Failed to load", effekseerWasmUrl);
    }
}

// 创建主程序实例并运行
const main = new Main();
main.run();

//-----------------------------------------------------------------------------